﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using up6.db.model;

namespace up6.db.utils
{
    public class CryptoTool
    {
        string key = "2C4DD1CC9KAX4TA9";
        string iv  = "2C4DD1CC9KAX4TA9";

        /// <summary>
        /// aes-cbc-解密
        /// </summary>
        /// <param name="txt"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public string decode(string txt)
        {
            byte[] buf= Convert.FromBase64String(txt);

            int lenAlign = 0;//对齐长度
            //16字节对齐
            if ((buf.Length % 16) > 0) lenAlign = 16 - buf.Length % 16;
            MemoryStream ms = new MemoryStream();
            //字节对齐
            ms.SetLength(buf.Length + lenAlign);
            ms.Write(buf, 0, buf.Length);

            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
            byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);

            RijndaelManaged rDel = new RijndaelManaged();
            rDel.Key = keyArray;
            rDel.IV = ivArray;
            rDel.Mode = CipherMode.CBC;
            rDel.Padding = PaddingMode.Zeros;

            ICryptoTransform cTransform = rDel.CreateDecryptor();
            byte[] ori = cTransform.TransformFinalBlock(ms.ToArray(), 0, (int)ms.Length);

            return UTF8Encoding.UTF8.GetString(ori,0,buf.Length).Trim();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stm">加密时此大小是16字节对齐</param>
        /// <param name="lenOri">原始块长度</param>
        /// <returns></returns>
        public MemoryStream decode(Stream stm,int lenOri)
        {
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
            byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);

            RijndaelManaged rDel = new RijndaelManaged();
            rDel.Key = keyArray;
            rDel.IV = ivArray;
            rDel.Mode = CipherMode.CBC;
            rDel.Padding = PaddingMode.Zeros;

            MemoryStream sec = new MemoryStream();
            int lenAlign = 0;//对齐长度
            //16字节对齐
            if ((stm.Length % 16) > 0) lenAlign = 16 - (int)stm.Length % 16;
            //块大小对齐
            sec.SetLength(stm.Length + lenAlign);
            stm.Seek(0, SeekOrigin.Begin);
            stm.CopyTo(sec);

            ICryptoTransform cTransform = rDel.CreateDecryptor();
            byte[] res = cTransform.TransformFinalBlock(sec.ToArray(), 0, (int)sec.Length);
            System.IO.MemoryStream ms = new System.IO.MemoryStream(res,0,lenOri);
            return ms;
        }

        /// <summary>
        /// 完善逻辑，补齐文本长度，必须是16的倍数
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public string encode(string v)
        {
            byte[] src= UTF8Encoding.UTF8.GetBytes(v);
            int lenAlign = 0;//对齐长度
            //16字节对齐
            if ((src.Length % 16)>0) lenAlign = 16 - src.Length % 16;
            MemoryStream ms = new MemoryStream();
            ms.SetLength(src.Length + lenAlign);
            ms.Write(src, 0, src.Length);

            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
            byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);

            RijndaelManaged rDel = new RijndaelManaged();
            rDel.Key = keyArray;
            rDel.IV = ivArray;
            rDel.Mode = CipherMode.CBC;
            rDel.Padding = PaddingMode.Zeros;

            ICryptoTransform tf = rDel.CreateEncryptor();
            byte[] resultArray = tf.TransformFinalBlock(ms.ToArray(), 0, (int)ms.Length);

            return Convert.ToBase64String(resultArray,Base64FormattingOptions.None);
        }

        /// <summary>
        /// 计算token，进行授权检查
        /// token = encode( md5(id+nameLoc))
        /// </summary>
        /// <param name="f"></param>
        /// <param name="action">动作：init,block,cmp</param>
        /// <returns></returns>
        public string token(FileInf f,string action="init")
        {
            string str = f.id + f.nameLoc + action;
            if (action == "block") str = f.id + f.pathSvr + action;
            str = this.md5(str);
            str = this.encode(str);
            return str;
        }

        public string md5(string s)
        {
            byte[] sor = Encoding.UTF8.GetBytes(s);
            MD5 md5 = MD5.Create();
            byte[] result = md5.ComputeHash(sor);
            StringBuilder strbul = new StringBuilder(40);
            for (int i = 0; i < result.Length; i++)
            {
                strbul.Append(result[i].ToString("x2"));//加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位

            }
            return strbul.ToString();
        }
    }
}